package bibliotheque.wave;

import java.util.ArrayList;
import java.util.concurrent.Semaphore;

/**
 * Cette classe contient les informations nécessaire à la propagation d'une vague sur un graphe quelconque (de qui est parvenu la vague, de qui attend t'on des acquitements....). Cette classe fourni aussi au WaveAgent deux mutex qui permettent de synchroniser correctement les traitements spécifiques à la vague.
 */
public class Wave {
    /**
     *Enumeration des etats possibles d'une vague.
     */
    public enum State {RUNNING, LOCALY_ENDED, GLOBALY_ENDED};
    /**
     *L'etat de la vague.
     */
    private State state;
    /**
     *L'identifiant de la vague.
     */
    private WaveId id;
    /**
     *Le stub du WaveAgent à qui on doit acquiter la vague.
     */
    private WaveAgentRemote up;
    /**
     *La liste des stubs de WaveAgent de qui on attend des acquitements.
     */
    private ArrayList<WaveAgentRemote> waits;
    /**
     *Ce semaphore doit etre bloque pour executer les traitements de la vague en exclusion mutuelle.
     */
    protected Semaphore mutex;
    /**
     *Ce semaphore doit etre bloque pour empecher le traitement d'un aquitement avant les traitements effectues à la propagation.
     */
    protected Semaphore first_mutex;
    
    /**
     *Le constructeur de la classe Wave.
     *@param id L'identificateur de la vague.
     *@param up Le stub du WaveAgent à qui on doit acquiter la vague.
     *@param waits La liste des stubs de WaveAgent de qui on attend des acquitements.
     */
    public Wave(WaveId id, WaveAgentRemote up, ArrayList<WaveAgentRemote> waits) {
        this.id = id;
        this.up = up;
        this.waits = waits;
        this.state = State.RUNNING;
        this.mutex = new Semaphore(1);
        this.first_mutex = new Semaphore(0);
    }
    
    /**
     *Supprime agent de la liste des WaveAgents de qui on attend des acquitements.
     *@param agent Le stub de WaveAgent a enlever de la liste.
     */
    public void Acknowledged(WaveAgentRemote agent) {
        this.waits.remove(agent);
    }
    
    /**
     *Obtient l'etat de la vague.
     *@return L'etat actuel de la vague.
     */
    public State GetState() {
        if(this.up == null && this.waits.size() == 0) this.state = State.GLOBALY_ENDED;
        else if(this.waits.size() == 0) this.state = State.LOCALY_ENDED;
        else this.state = State.RUNNING;
        return(this.state);
    }
    
    /**
     *Obtient le stub du WaveAgent à qui la vague doit etre acquitee.
     *@return Le stub du WaveAgent à qui la vague doit etre acquitee.
     */
    public WaveAgentRemote GetUp() {
        return(this.up);
    }
}
